using System;
using System.Collections.Generic;
using System.Threading;
using System.Web.Security;
using System.Security.Principal;
using System.ServiceModel;

namespace SecurityAgent
{
    /// <summary>
    /// Web service role provider. 
    /// </summary>
    public class SecurityAgentRoleProvider : System.Web.Security.RoleProvider
    {
        private string _applicationName;
        private string _applicationKey;
        private string _serviceEndPoint;

        private RoleProviderServiceReference.RoleProviderServiceClient _serviceClient;

        public RoleProviderServiceReference.RoleProviderServiceClient ServiceClient
        {
            get
            {
                if (_serviceClient == null)
                {
                    if (String.IsNullOrEmpty(_serviceEndPoint))
                    {
                        _serviceClient = new RoleProviderServiceReference.RoleProviderServiceClient();
                    }
                    else
                    {
                        _serviceClient = new RoleProviderServiceReference.RoleProviderServiceClient(_serviceEndPoint);
                    }
                }

                return _serviceClient;
            }
        }


        private SASIdentity _sasIdentity;

        public string CurrentUserToken
        {
            get
            {
                if (_sasIdentity == null)
                {
                    _sasIdentity = (SASIdentity)Thread.CurrentPrincipal.Identity;
                }

                if (_sasIdentity == null)
                    return string.Empty;
                else
                    return _sasIdentity.UserToken;
            }
        }
        /// <summary>
        /// Initialize the provider. 
        /// </summary>
        /// <remarks>Part of the initialization process includes establishing a session with the remote provider for security.</remarks>
        /// <param name="name"></param>
        /// <param name="config"></param>
        public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)
        {
            base.Initialize(name, config);

            /// Url is now configured and managed in the endpoint binding configuration. There is no need to allow multiple endpoints to the securityagent services.
            //string url = this.GetConfigValue(config["ServiceUrl"], string.Empty);
            //if (string.IsNullOrEmpty(url))
            //    throw new ArgumentNullException("Missing ServiceUrl key in role provider configuration.");

            //this.sUrl = url;  

            _applicationKey = this.GetConfigValue(config["applicationKey"], "");
            _serviceEndPoint = this.GetConfigValue(config["serviceEndPoint"], "");
            _applicationName = this.GetConfigValue(config["applicationName"], "");
        }

        private string GetConfigValue(string configValue, string defaultValue)
        {
            if (String.IsNullOrEmpty(configValue))
                return defaultValue;

            return configValue;
        }

        public override void AddUsersToRoles(string[] usernames, string[] roleNames)
        {
            try
            {
                ServiceClient.AddUsersToRoles(_applicationKey, CurrentUserToken, usernames, roleNames);
            }
            catch (FaultException<UnauthorizedAccessFault> e1)
            {
                throw new UnauthorizedAccessException(e1.Detail);
            }
            catch (FaultException<SecurityFault> e2)
            {
                throw new GeneralSecurityException(e2.Detail);
            }
            catch (FaultException e3)
            {
                throw new Exception(e3.Message + ":" + e3.Reason);
            }
        }

        public override string ApplicationName
        {
            get
            {
                return _applicationName;
            }
            set
            {
                _applicationName = value;
            }
        }

        public override void CreateRole(string roleName)
        {
            try
            {
                ServiceClient.CreateRole(_applicationKey, CurrentUserToken, roleName);
            }
            catch (FaultException<UnauthorizedAccessFault> e1)
            {
                throw new UnauthorizedAccessException(e1.Detail);
            }
            catch (FaultException<SecurityFault> e2)
            {
                throw new GeneralSecurityException(e2.Detail);
            }
            catch (FaultException e3)
            {
                throw new Exception(e3.Message + ":" + e3.Reason);
            }
        }

        public override bool DeleteRole(string roleName, bool throwOnPopulatedRole)
        {
            try
            {
                ServiceClient.DeleteRole(_applicationKey, CurrentUserToken, roleName, throwOnPopulatedRole);

                return true;
            }
            catch (FaultException<UnauthorizedAccessFault> e1)
            {
                throw new UnauthorizedAccessException(e1.Detail);
            }
            catch (FaultException<SecurityFault> e2)
            {
                throw new GeneralSecurityException(e2.Detail);
            }
            catch (FaultException e3)
            {
                throw new Exception(e3.Message + ":" + e3.Reason);
            }


        }

        public override string[] FindUsersInRole(string roleName, string usernameToMatch)
        {
            try
            {
                return ServiceClient.FindUsersInRole(_applicationKey, CurrentUserToken, roleName, usernameToMatch);
            }
            catch (FaultException<UnauthorizedAccessFault> e1)
            {
                throw new UnauthorizedAccessException(e1.Detail);
            }
            catch (FaultException<SecurityFault> e2)
            {
                throw new GeneralSecurityException(e2.Detail);
            }
            catch (FaultException e3)
            {
                throw new Exception(e3.Message + ":" + e3.Reason);
            }
        }

        public override string[] GetAllRoles()
        {
            try
            {
                RoleProviderServiceReference.RoleCollection ret = ServiceClient.GetAllRoles(_applicationKey, CurrentUserToken);

                if (ret != null) return ret.ToArray();
                else
                    return null;
            }
            catch (FaultException<UnauthorizedAccessFault> e1)
            {
                throw new UnauthorizedAccessException(e1.Detail);
            }
            catch (FaultException<SecurityFault> e2)
            {
                throw new GeneralSecurityException(e2.Detail);
            }
            catch (FaultException e3)
            {
                throw new Exception(e3.Message + ":" + e3.Reason);
            }

        }

        public override string[] GetRolesForUser(string username)
        {
            try
            {
                RoleProviderServiceReference.RoleCollection ret = ServiceClient.GetRolesForUser(_applicationKey, CurrentUserToken, username);
                if (ret != null) return ret.ToArray();
                else
                    return null;
            }
            catch (FaultException<UnauthorizedAccessFault> e1)
            {
                throw new UnauthorizedAccessException(e1.Detail);
            }
            catch (FaultException<SecurityFault> e2)
            {
                throw new GeneralSecurityException(e2.Detail);
            }
            catch (FaultException e3)
            {
                throw new Exception(e3.Message + ":" + e3.Reason);
            }
        }

        public override string[] GetUsersInRole(string roleName)
        {
            try
            {
                return ServiceClient.GetUsersInRole(_applicationKey, CurrentUserToken, roleName);
            }
            catch (FaultException<UnauthorizedAccessFault> e1)
            {
                throw new UnauthorizedAccessException(e1.Detail);
            }
            catch (FaultException<SecurityFault> e2)
            {
                throw new GeneralSecurityException(e2.Detail);
            }
            catch (FaultException e3)
            {
                throw new Exception(e3.Message + ":" + e3.Reason);
            }
        }

        public override bool IsUserInRole(string username, string roleName)
        {
            try
            {
                return ServiceClient.IsUserInRole(_applicationKey, CurrentUserToken, username, roleName);
            }
            catch (FaultException<UnauthorizedAccessFault> e1)
            {
                throw new UnauthorizedAccessException(e1.Detail);
            }
            catch (FaultException<SecurityFault> e2)
            {
                throw new GeneralSecurityException(e2.Detail);
            }
            catch (FaultException e3)
            {
                throw new Exception(e3.Message + ":" + e3.Reason);
            }
        }

        public override void RemoveUsersFromRoles(string[] usernames, string[] roleNames)
        {
            try
            {
                ServiceClient.RemoveUsersFromRoles(_applicationKey, CurrentUserToken, usernames, roleNames);
            }
            catch (FaultException<UnauthorizedAccessFault> e1)
            {
                throw new UnauthorizedAccessException(e1.Detail);
            }
            catch (FaultException<SecurityFault> e2)
            {
                throw new GeneralSecurityException(e2.Detail);
            }
            catch (FaultException e3)
            {
                throw new Exception(e3.Message + ":" + e3.Reason);
            }
        }

        public override bool RoleExists(string roleName)
        {
            try
            {
                return ServiceClient.RoleExists(_applicationKey, CurrentUserToken, roleName);
            }
            catch (FaultException<UnauthorizedAccessFault> e1)
            {
                throw new UnauthorizedAccessException(e1.Detail);
            }
            catch (FaultException<SecurityFault> e2)
            {
                throw new GeneralSecurityException(e2.Detail);
            }
            catch (FaultException e3)
            {
                throw new Exception(e3.Message + ":" + e3.Reason);
            }
        }


    }

}
